package hasher

import (
	"bufio"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"io"
	"os"

	"gitee.com/gousing/helper/internal"
)

// Sha1 （40位）小写Hex字符串
func Sha1(in string) string {
	return hex.EncodeToString(Sha1Byte(internal.StringToBytes(in)))
}

// Sha1Byte （20位）Hex字节数组
func Sha1Byte(in []byte) []byte {
	if len(in) == 0 {
		in = []byte{}
	}
	h := sha1.Sum(in)
	return h[:]
}

// Sha1File （40位）小写Hex字符串
func Sha1File(filePath string) (string, error) {
	data, err := Sha1FileBytes(filePath)
	if err != nil {
		return "", err
	}
	return hex.EncodeToString(data), nil
}

// Sha1FileBytes （20位）Hex字节数组
func Sha1FileBytes(filePath string) ([]byte, error) {
	if len(filePath) == 0 {
		return []byte{}, errors.New("Sha1HmacByte: filePath is empty")
	}
	file, err := os.Open(filePath)
	if err != nil {
		return []byte{}, err
	}
	defer file.Close()
	h := sha1.New()
	reader := bufio.NewReader(file)
	buf := make([]byte, 4096) // 4KB的缓冲区
	for {
		n, err := reader.Read(buf)
		if err != nil && err != io.EOF {
			return []byte{}, err
		}
		if n == 0 {
			break
		}
		h.Write(buf[:n])
	}
	return h.Sum(nil), nil
}

// Sha1Hmac （40位）小写Hex字符串
func Sha1Hmac(in, key string) string {
	return hex.EncodeToString(Sha1HmacByte(internal.StringToBytes(in), internal.StringToBytes(key)))
}

// Sha1HmacByte （20位）Hex字节数组
func Sha1HmacByte(in, key []byte) []byte {
	if len(in) == 0 {
		in = []byte{}
	}
	if len(key) == 0 {
		panic("Sha1HmacByte: key is empty")
	}
	hash := hmac.New(sha1.New, key)
	hash.Write(in)
	return hash.Sum(nil)
}

// Sha1HmacFile （40位）小写Hex字符串
func Sha1HmacFile(filePath, key string) (string, error) {
	data, err := Sha1HmacFileBytes(filePath, internal.StringToBytes(key))
	if err != nil {
		return "", err
	}
	return hex.EncodeToString(data), nil
}

// Sha1HmacFileBytes （20位）Hex字节数组
func Sha1HmacFileBytes(filePath string, key []byte) ([]byte, error) {
	if len(filePath) == 0 {
		return []byte{}, errors.New("Sha1HmacByte: filePath is empty")
	}
	if len(key) == 0 {
		return []byte{}, errors.New("Sha1HmacByte: key is empty")
	}
	file, err := os.Open(filePath)
	if err != nil {
		return []byte{}, err
	}
	defer file.Close()
	h := hmac.New(sha1.New, key)
	reader := bufio.NewReader(file)
	buf := make([]byte, 4096) // 4KB的缓冲区
	for {
		n, err := reader.Read(buf)
		if err != nil && err != io.EOF {
			return []byte{}, err
		}
		if n == 0 {
			break
		}
		h.Write(buf[:n])
	}
	return h.Sum(nil), nil
}
